package org.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@SpringBootApplication // 标记为 SpringBoot 的应用
@EnableDiscoveryClient // 开启服务的发现功能
@RestController
public class ConsumerApplication {


    public static void main(String[] args) {

        SpringApplication.run(ConsumerApplication.class,args) ;
    }

    @Autowired
    private DiscoveryClient discoveryClient ;// 快速服务的发现

    @GetMapping("/discovery/{serviceName}")
    public ResponseEntity<List<String>> discovery(@PathVariable("serviceName") String serviceName){


        //通过服务的 ID / 名称得到服务的实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        if(instances==null || instances.isEmpty()){


            return ResponseEntity.notFound().build() ;
        }
        List<String> services = new ArrayList<>(instances.size());
        instances.forEach(instance->{


            services.add(instance.getHost()+":"+instance.getPort());
        });
        return ResponseEntity.ok(services) ;
    }

    //在容器里面注入一个 RestTempalte 对象
    @Bean
    @LoadBalanced //config中的RestTemplate上添加一个@LoadBalanced注解，让服务器知道采用轮询的负载均衡方式进行请求即可
    public RestTemplate restTemplate(){


        return new RestTemplate() ;
    }

    @Autowired
    private RestTemplate restTemplate ;

    @GetMapping("/rpcv1/{message}")
    public ResponseEntity<String> rpcV1(@PathVariable("message") String message){


        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                "http://localhost:8001/echo/{message}",
                String.class,
                message
        );
        if(responseEntity.getStatusCode()==HttpStatus.OK){


            return ResponseEntity.ok(String.format("远程调用成功，结果为%s",responseEntity.getBody())) ;
        }
        return ResponseEntity.badRequest().body("远程调用失败") ;
    }

    //优化服务提供方地址的灵活性
    @GetMapping("/rpcv2/{message}")
    public ResponseEntity<String> rpcV2(@PathVariable("message") String message){


        List<ServiceInstance> instances = discoveryClient.getInstances("provider-service");
        if(instances==null || instances.isEmpty()){


            return ResponseEntity.badRequest().body("当前服务没有服务的提供者") ;
        }
        ServiceInstance serviceInstance = instances.get(0);
        String instance = serviceInstance.getHost()+":"+serviceInstance.getPort() ;
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                String.format("http://%s/echo/{message}",instance),
                String.class,
                message
        );
        if(responseEntity.getStatusCode()== HttpStatus.OK){


            return ResponseEntity.ok(String.format("远程调用成功，结果为%s",responseEntity.getBody())) ;
        }
        return ResponseEntity.badRequest().body("远程调用失败") ;
    }

    //优化服务提供方的负载均衡
    @GetMapping("/rpcv3/{message}")
    public ResponseEntity<String> rpcV3(@PathVariable("message") String message){


        List<ServiceInstance> instances = discoveryClient.getInstances("provider-service");
        if(instances==null || instances.isEmpty()){


            return ResponseEntity.badRequest().body("当前服务没有服务的提供者") ;
        }
        ServiceInstance serviceInstance = loadbalance(instances);
        System.out.println(serviceInstance);
        String instance = serviceInstance.getHost()+":"+serviceInstance.getPort() ;
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                String.format("http://%s/echo/{message}",instance),
                String.class,
                message
        );
        if(responseEntity.getStatusCode()==HttpStatus.OK){


            return ResponseEntity.ok(String.format("远程调用成功，结果为%s",responseEntity.getBody()));
        }
        return ResponseEntity.badRequest().body("远程调用失败");
    }

    //从一个服务的实例列表里面选择一个服务的实例
    private ServiceInstance loadbalance(List<ServiceInstance> instances) {
        Random random = new Random(System.currentTimeMillis());
        return instances.get(random.nextInt(instances.size()));
    }

    @Autowired
    private LoadBalancerClient loadBalancerClient ;

    @GetMapping("/choose/{serviceName}")
    public ResponseEntity<String> choose(@PathVariable("serviceName") String serviceName){
        ServiceInstance instance = loadBalancerClient.choose(serviceName);
        System.out.println(String.format("本次选择的实例为：%s:%s",instance.getHost(),instance.getPort()));
        return ResponseEntity.ok(instance.getHost()+":"+instance.getPort()) ;
    }

    @GetMapping("/rpc/ribbon/{message}")
    public ResponseEntity<String> rpcByRibbon(@PathVariable("message") String message){


        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://provider-service/echo/" + message,String.class);
        if(responseEntity.getStatusCode()==HttpStatus.OK){


            return ResponseEntity.ok("调用成功，provider-service 相应给我们的数据为："+responseEntity.getBody()) ;
        }
        return ResponseEntity.badRequest().body("调用失败，provider-service 的相应码为："+responseEntity.getStatusCode()) ;
    }
}